﻿using HamcoWcs.Contract.ContractCommon;
using HamcoWcs.Contract.ContractMainTask.IMainTaskParsers;
using HamcoWcs.Entitys.MainTasks;
using HamcoWcs.Entitys.SubTasks;
using HamcoWcs.Entitys.WcsLocations;
using HamcoWcs.Models.Common;
using HamcoWcs.Models.Common.Enums;
using HamcoWcs.Models.EdgeInfos;
using HamcoWcs.Models.ForeEndModels.UITasks;
using HamcoWcs.Models.WcsLocations;
using HamcoWcs.Service.Common;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Linq.Expressions;

namespace HamcoWcs.Service.MainTasks.SubTaskParsers
{    /// <summary>
     /// Srm盘点任务解析器
     /// </summary>
    [AutoInject(typeof(ISubTaskParser), InjectType.Scope)]
    public class SubTaskParser_SrmInventoryTask : SubTaskParserBase
    {

        private readonly ILoggerService _logger;
        private readonly IBaseConfigService _baseConfigService;
        public override EnumSubTaskType SubTaskType => EnumSubTaskType.SrmInventoryTask;
        public SubTaskParser_SrmInventoryTask(ILoggerService logger, ILocationService locationService, IBaseConfigService baseConfigService, AutomaticStorageInfo asrs) : base(locationService)
        {
            _baseConfigService = baseConfigService;
            _logger = logger;
            _asrs = asrs;
        }


        public override void Deal(MainTask mainTask, EdgeInfoDto edge)
        {
            var inventoryInfo = JsonConvert.DeserializeObject<InventoryTaskInfo>(mainTask.InventoryInfo);
            if (inventoryInfo == null) throw new Exception($"未获取到盘点任务信息");

            HandleShelf(inventoryInfo); // 全局或者指定堆垛机时填充Shelves字段

            if (inventoryInfo.Shelves.Length == 0)
            {
                _logger.AddWcsRunLog("", $"创建盘点任务{mainTask.TaskId}时未指定储位");
                mainTask.TaskStatus = "Cancel";

            }; // 一般不会发生，数据库无储位信息时会触发
            mainTask.InventoryInfo = JsonConvert.SerializeObject(inventoryInfo);

            var locs = _locationService.GetAllLoc().ToDictionary(k => k.WcsLocName, v => v);
            foreach (var shelf in inventoryInfo.Shelves)
            {
                bool isExists = locs.TryGetValue(shelf, out WcsLocation loc);

                if (!isExists)
                {
                    _logger.AddSystemErrorLog($"TaskId:{mainTask.TaskId},创建盘点任务时未找到对应的储位[{shelf}]");
                    continue;
                }
                if (loc.IsLock || loc.SrmOccupyFlag)
                {
                    _logger.AddSystemErrorLog($"TaskId:{mainTask.TaskId},创建盘点任务时储位[{shelf}]已锁定");
                    continue;
                }

                var subTask = CreateNewSubTask(mainTask, loc, inventoryInfo);
                mainTask.SubTasks.Add(subTask);
            }
        }

        private SubTask CreateNewSubTask(MainTask mainTask, WcsLocation loc, InventoryTaskInfo inventoryInfo)
        {
            var plcName = "";


            if (string.IsNullOrEmpty(inventoryInfo.TargetSrm))
            {
                plcName = loc.Aisle;
            }
            else
            {
                var aisle = inventoryInfo.TargetSrm.Split('-')[0];

                var node = _asrs.Nodes.FirstOrDefault(x => x.NodeName == aisle);
                if (node.AisleMode == EnumSrmAisleMode.OneDisable)
                {
                    var srm = node.GetEnabledSrm();
                    plcName = srm.SrmName;
                }
                else
                {
                    plcName = GetInventrySrm(inventoryInfo);
                }
            }


            return new SubTask()
            {
                TaskFrom = mainTask.Sender,
                SubTaskId = "",
                SubTaskType = SubTaskType.ToString(),
                TaskStatus = EnumSubTaskStatus.NewTask.ToString(),
                UnitId = "",
                TaskSeq = mainTask.SubTasks.Count + 1,
                FromLoc = "",
                ToLoc = loc.WcsLocName,
                PlcName = plcName,
            };
        }

        private string GetInventrySrm(InventoryTaskInfo info)
        {
            if (info.TargetSrm.ToUpper() == "CJSTW100-C1") return "Srm01";
            if (info.TargetSrm.ToUpper() == "CJSTW100-C2") return "Srm02";
            if (info.TargetSrm.ToUpper() == "CJSTW200-C1") return "Srm03";
            if (info.TargetSrm.ToUpper() == "CJSTW200-C2") return "Srm04";
            return "";
        }

        private void HandleShelf(InventoryTaskInfo taskInfo)
        {
            if (taskInfo.Mode == EnumInventoryMode.BySrm)
            {
                var loc = _locationService.GetInventoryShelfInfo();
                var t = taskInfo.TargetSrm.Split('-');
                string machineName = t[0];
                string portName = t[1];


                int sBay = GetSeparatorBay(machineName);
                var lambda = GetLambda<ShelfInfoDto>("Bay", sBay, portName.Equals("C1"));
                taskInfo.Shelves = loc.Values.Where(x => x.Aisle == machineName)
                    .Where(lambda).Select(x => x.WcsLocName).ToArray();
            }



            //switch (taskInfo.Mode)
            //{

            //    case EnumInventoryMode.BySrm:
            //        var t = taskInfo.TargetSrm.Split('-');
            //        string machineName = t[0];
            //        string portName = t[1];


            //        int sBay = GetSeparatorBay(machineName);
            //        var lambda = GetLambda<ShelfInfoDto>("Bay", sBay, portName.Equals("C1"));
            //        taskInfo.Shelves = loc.Values.Where(x => x.Aisle == machineName)
            //            .Where(lambda).Select(x => x.WcsLocName).ToArray();
            //        break;
            //    //case EnumInventoryMode.All:
            //    //    taskInfo.Shelves = loc.Values.Select(x => x.WcsLocName).ToArray();
            //    //    break;
            //    case EnumInventoryMode.ByShelf:
            //    default:
            //        break;
            //}
        }

        private int GetSeparatorBay(string machineName)
        {
            string key = $"{machineName}_INVENTORY_SEPARATOR_BAY";
            int bay = machineName.Equals("CJSTW100") ? GlobalValue.CJSTW100_MID_BAY : GlobalValue.CJSTW200_MID_BAY;
            try
            {
                bay = int.Parse(_baseConfigService.GetConfigValue(key));
            }
            catch (Exception)
            {

            }

            return bay;
        }

        private readonly AutomaticStorageInfo _asrs;
        private static Func<T, bool> GetLambda<T>(string propName, object value, bool flag)
        {
            var param = Expression.Parameter(typeof(T), "x");
            var paramPi = Expression.Property(param, propName);
            var constant = Expression.Constant(value);
            var equalExp = flag ? Expression.LessThanOrEqual(paramPi, constant) : Expression.GreaterThan(paramPi, constant);
            var lambda = Expression.Lambda<Func<T, bool>>(equalExp, param);
            return lambda.Compile();
        }



    }
}
